#if !defined(NodeHeader)
#define NodeHeader

#include <string>
#include <typeinfo>

#include "parse.h"
#include "pointer.h"

class Atom;
class Trail;
class Number;
class Reference;
class Tree;
class Tuple;
class Switcher;
class pNode;

class Node {
public:
  Node () :
    referenceCount (0) {
  }
  virtual ~Node () {
  }

  // Both to-string functions are similar but with formatting differences
  virtual std::string dump (int = 0) = 0; // Machine-readable format
  virtual std::string display (int = 0) = 0; // Human-readable format

  // Standard procedure for upcast, kind of clumsy:
  // - Call final() to ensure the copy is not a reference
  // - Call type() to confirm object type
  // - static_cast to what you like (Do not want RTTI so no dynamic_cast)
  typedef char NodeType;
  virtual NodeType type () const = 0;

  Node *final ();

  virtual pNode replicate ();

  virtual void bound (Node&, Trail&) {
  } // Only for unbinded

  virtual void unbound () {
  } // If this was bounded before

  virtual bool doSwitch (Switcher&) = 0;

  static Node *parse (const std::string &input) {
    return parseNode (removeComments (input));
  }

  int referenceCount;
};

int compareNodes (Node&, Node&); // Returns -1, 0 or 1

bool isTrue (Node&); // True, TRUE, yes, YES, non-zeroes are true

class pNode : public ReferenceCountedPointer<Node> {
public:
  pNode () {
  }

  pNode (Node *e) :
    ReferenceCountedPointer<Node> (e) {
  }

  pNode (const pNode &p) :
    ReferenceCountedPointer<Node> (p) {
  }

  pNode (const std::string&); // Parses from string

  ~pNode () {
  }

  operator Node* () const {
    return node;
  }

  std::string dump () {
    return node->dump (0);
  }

  std::string display () const {
    return node->display (0);
  }

  Node::NodeType type () const {
    return node->type ();
  }

  Node *final () const {
    return node->final ();
  }

  void bound (Node &n, Trail &j) {
    node->bound (n, j);
  }

  bool doSwitch (Switcher& switcher) {
    return node->doSwitch (switcher);
  }

  // Comparison function for use in std::map
  bool operator < (const pNode &p) const {
    return node < p.node;
  }
};

// Operators array definition
struct Operator {
  const char *name;
  int rightAssociation;
};

extern Operator const operators[];
extern int const nOperators;

#endif
